#include "prec.h"
#include "uielement.h"
#include <wx/listimpl.cpp>

WX_DEFINE_LIST(wxDUIElementList);

IMPLEMENT_ABSTRACT_CLASS(wxDUIElement, wxObject);

wxDUIElement::wxDUIElement()
	: mParent(NULL)
	, mLeft(NULL)
	, mRight(NULL)
	, mShown(true)
	, mId(wxEmptyString)
	, mPosition(wxDefaultPosition)
	, mSize(wxDefaultSize)
{
	mChildren.DeleteContents(true);
}

wxDUIElement::wxDUIElement( wxDUIElement* parent, 
						   const wxString& id /*= wxEmptyString*/, 
						   const wxPoint& position /*= wxDefaultPosition*/, 
						   const wxSize& size /*= wxDefaultSize */ )
						   : mParent(parent)
						   , mLeft(NULL)
						   , mRight(NULL)
						   , mShown(true)
						   , mId(wxEmptyString)
						   , mPosition(position)
						   , mSize(size)
{
	mChildren.DeleteContents(true);
}

wxDUIElement::~wxDUIElement()
{
	mChildren.Clear();
}

void wxDUIElement::AppendChild( wxDUIElement* element )
{
	wxASSERT(element);

	if (AllowAddChild(element))
	{	
		wxDUIElementList::compatibility_iterator node = mChildren.Append(element);
		
		LinkElement(node);
	}
	else
	{
		throw wxDException(InvalidCalling);
	}
}

void wxDUIElement::PrependChild( wxDUIElement* element )
{
	wxASSERT(element);

	if (AllowAddChild(element))
	{
		wxDUIElementList::compatibility_iterator node = mChildren.Insert(element);

		LinkElement(node);
	}
	else
	{
		throw wxDException(InvalidCalling);
	}
}

void wxDUIElement::InsertChild( int index, wxDUIElement* element )
{
	wxASSERT(index >= 0 && element);

	if (AllowAddChild(element))
	{
		wxDUIElementList::compatibility_iterator node = mChildren.Insert(index, element);

		LinkElement(node);
	}
	else
	{
		throw wxDException(InvalidCalling);
	}
}

wxDUIElement* wxDUIElement::GetChild( int index ) const
{
	wxDUIElementList::compatibility_iterator node = mChildren.Item(index);

	if (node)
		return node->GetData();

	return NULL;
}

wxDUIElement* wxDUIElement::GetChild( const wxString& id ) const
{
	for (wxDUIElementList::const_iterator it = mChildren.begin(); it != mChildren.end(); ++it)
	{
		wxDUIElement* element = *it;
		if (element->GetId() == id)
			return element;
	}

	return NULL;
}

wxDUIElement* wxDUIElement::FindChild( const wxString& id ) const
{
	for (wxDUIElementList::const_iterator it = mChildren.begin(); it != mChildren.end(); ++it)
	{
		wxDUIElement* element = *it;
		if (element->GetId() == id)
		{
			return element;
		}
		else
		{
			wxDUIElement* child = element->FindChild(id);
			if (child) return child;
		}
	}

	return NULL;
}

bool wxDUIElement::RemoveChild( wxDUIElement* element )
{
	wxDUIElementList::compatibility_iterator node = mChildren.Find(element);

	if (node && AllowRemoveChild(node->GetData()))
	{
		UnlinkElement(node);

		node->SetData(NULL);
		mChildren.DeleteNode(node);
		return true;
	}

	return false;
}

wxDUIElement* wxDUIElement::RemoveChild( int index )
{
	wxDUIElementList::compatibility_iterator node = mChildren.Item(index);
	wxDUIElement* element = NULL;

	if (node && AllowRemoveChild(node->GetData()))
	{
		UnlinkElement(node);

		element = node->GetData();
		node->SetData(NULL);
		mChildren.DeleteNode(node);
	}

	return element;
}

wxDUIElement* wxDUIElement::RemoveChild( const wxString& id )
{
	wxDUIElementList::compatibility_iterator node = mChildren.GetFirst();

	while (node)
	{
		wxDUIElement* element = node->GetData();
		if (element->GetId() == id && AllowRemoveChild(element))
		{
			UnlinkElement(node);
			node->SetData(NULL);
			mChildren.DeleteNode(node);
			return element;
		}

		node = node->GetNext();
	}

	return NULL;
}

void wxDUIElement::RemoveChildren()
{
	mChildren.DeleteContents(false);
	mChildren.Clear();
	mChildren.DeleteContents(true);
}

bool wxDUIElement::DestoryChild( int index )
{
	wxDUIElementList::compatibility_iterator node = mChildren.Item(index);
	
	if (node && AllowRemoveChild(node->GetData()))
	{
		UnlinkElement(node);

		mChildren.DeleteNode(node);
		return true;
	}

	return false;
}

bool wxDUIElement::DestoryChild( const wxString& id )
{
	wxDUIElementList::compatibility_iterator node = mChildren.GetFirst();

	while (node)
	{
		wxDUIElement* element = node->GetData();
		if (element->GetId() == id && AllowRemoveChild(element))
		{
			UnlinkElement(node);
			
			mChildren.DeleteNode(node);
			return true;
		}

		node = node->GetNext();
	}

	return false;
}

void wxDUIElement::DestoryChildren()
{
	mChildren.Clear();
}

wxDUIElement* wxDUIElement::GetGrandParent() const
{
	if (mParent)
	{
		return mParent->GetParent();
	}

	return NULL;
}

wxDUIElement* wxDUIElement::GetRoot() const
{
	wxDUIElement* element = mParent;

	while (element)
	{
		element = element->GetParent();
	}

	return element;
}

void wxDUIElement::LinkElement( wxDUIElementList::compatibility_iterator node )
{
	if (node)
	{
		wxDUIElement* element = node->GetData();
		wxDUIElementList::compatibility_iterator prevnode = node->GetPrevious();
		wxDUIElementList::compatibility_iterator nextnode = node->GetNext();

		if ( prevnode )
		{
			wxDUIElement* prev = prevnode->GetData();
			prev->SetNext(element);
			element->SetPrev(prev);
		}
		else
		{
			element->SetPrev(NULL);
		}

		if (nextnode)
		{
			wxDUIElement* next = nextnode->GetData();
			next->SetPrev(element);
			element->SetNext(next);
		}
		else
		{
			element->SetNext(NULL);
		}
	}
}

void wxDUIElement::UnlinkElement( wxDUIElementList::compatibility_iterator node )
{
	if (node)
	{
		wxDUIElement* element = node->GetData();
		wxDUIElementList::compatibility_iterator prevnode = node->GetPrevious();
		wxDUIElementList::compatibility_iterator nextnode = node->GetNext();

		if ( prevnode )
		{
			wxDUIElement* prev = prevnode->GetData();
			prev->SetNext(element->GetNextSibling());
		}

		if (nextnode)
		{
			wxDUIElement* next = nextnode->GetData();
			next->SetPrev(element->GetPrevSibling());
		}

		element->SetPrev(NULL);
		element->SetNext(NULL);
	}
}

wxDUIElement* wxDUIElement::GetFirstChild() const
{
	wxDUIElementList::compatibility_iterator node = mChildren.GetFirst();
	
	return node ? node->GetData() : NULL;
}

wxDUIElement* wxDUIElement::GetLastChild() const
{
	wxDUIElementList::compatibility_iterator node = mChildren.GetLast();

	return node ? node->GetData() : NULL;
}

const wxDUIElementList wxDUIElement::AsList() const
{
	wxDUIElementList elelist;

	AsList(elelist);

	return elelist;
}

void wxDUIElement::AsList( wxDUIElementList& elelist ) const
{
	elelist.Append((wxDUIElement*)this);

	for (wxDUIElementList::const_iterator it = mChildren.begin(); it != mChildren.end(); ++it)
	{
		wxDUIElement* element = *it;
		element->AsList(elelist);
	}
}

